package ivf

import (
	"encoding/json"
	"fmt"
	"sort"

	cuckoo "github.com/tendermint/tendermint/my_app/querylayer/vindex/ivf/cuckoofilter"
)

// InvertedIndex 表示倒排索引的结构
type InvertedIndex struct {
	Index       map[int][]Posting      // 从词项到倒排记录列表的映射
	Docs        map[int]BOW            // 存储文档ID到文档的映射，方便查询文档内容
	Digest      map[int]([]byte)       //前向哈希值 = hash(filter + weight + prevhash)
	Filter      map[int]*cuckoo.Filter //过滤器
	Weight      map[int]int            //权重（现是文档数）
	ObjectIDmap map[int]string
	ObCondition map[string]bool
}

// NewInvertedIndex 创建一个新的倒排索引
func NewInvertedIndex() *InvertedIndex {
	codebook = make(map[int]int)

	index := &InvertedIndex{
		Index:       make(map[int][]Posting),
		Docs:        make(map[int]BOW),
		Digest:      make(map[int][]byte),
		Filter:      make(map[int]*cuckoo.Filter),
		Weight:      make(map[int]int),
		ObjectIDmap: make(map[int]string),
		ObCondition: make(map[string]bool),
	}

	return index
}

func (index *InvertedIndex) Insert(objid string, doc BOW) error {

	index.Docs[doc.ID] = doc
	// words := strings.Fields(doc.Text) // 简单的分词，基于空格
	// wordFreq := make(map[string]int)
	var sum int
	for _, freq := range doc.Vector {
		if freq != 0 {
			sum++
		}
	}
	// sum := len(doc.vector)
	for word, freq := range doc.Vector {
		if freq == 0 {
			continue
		}
		posting := Posting{DocID: doc.ID, TF: float64(freq) / float64(sum)}
		index.Index[word] = append(index.Index[word], posting)
		if _, ok := index.Filter[word]; !ok {
			codebook[word] = len(codebook)
			index.Filter[word] = cuckoo.NewFilter(1000)
		}
		index.Filter[word].Insert(IntToBytes(doc.ID))
	}
	index.ObjectIDmap[doc.ID] = objid
	index.ObCondition[objid] = true
	return nil
}

func (index *InvertedIndex) Knn_Search(query []float32, k int) ([]string, [][]float32, []byte) {
	result, vectors := index.kNearestNeighbors(query, k)
	fmt.Printf("knn search resultlen=%d\n,k=%d", len(result), k)
	var result_BOW []BOW
	var objid []string
	for i := range result {
		result_BOW = append(result_BOW, index.Docs[i])
		objid = append(objid, index.ObjectIDmap[i])
	}
	//构建VO
	candidates := index.PostingSearch(query, result)
	fmt.Printf("search result:%s", objid)

	VO := index.GetVO(candidates)
	proof := TextProof{
		VO:        VO,
		ResultBOW: result_BOW,
	}
	proofjson, err := json.Marshal(proof)
	if err != nil {
		fmt.Printf("error")
	}
	return objid, vectors, proofjson
}

// 返回文档 ID 的切片
func (index *InvertedIndex) kNearestNeighbors(query []float32, k int) ([]int, [][]float32) {
	similarities := make([]DocSimilarity, len(index.Docs))
	fmt.Printf("len(index.Docs)=%d", len(index.Docs))
	i := 0
	for key, doc := range index.Docs {
		if index.isdeleted(key) {
			continue
		}
		similarity := cosineSimilarity(doc.Vector, query)
		similarities[i] = DocSimilarity{Doc: doc, Sim: similarity}
		i++
	}

	sort.Sort(BySimilarity(similarities))

	// 返回前 k 个相似度最高的文档 ID
	if k > len(similarities) {
		k = len(similarities)
	}

	result := make([]int, k)
	vectors := make([][]float32, 0)
	for i := 0; i < k; i++ {
		result[i] = similarities[i].Doc.ID
		vectors = append(vectors, similarities[i].Doc.Vector)
		fmt.Printf("knn search result i=%d\n", i)
	}
	return result, vectors
}

func (index *InvertedIndex) Delete(objectid string) error {
	//fmt.Println("index delete object:", objectid)
	_, exists := index.ObCondition[objectid]
	if !exists {
		return fmt.Errorf("object dosen't exist")
	} else {
		index.ObCondition[objectid] = false
	}
	return nil
}

func (index *InvertedIndex) isdeleted(key int) bool {
	if index.ObCondition[index.ObjectIDmap[key]] {
		return false
	} else {
		return true
	}
}
